/**
 *    @file       maintainudptask.cpp
 *
 *    @brief      
 *    @details
 *
 *    @version    1.0
 *    @date       02/17/2014 04:11:10 PM
 *
 *    @author     Theophilus (), wangtf418@gmail.com */
#include "maintainudptask.h"
#include "server.h"


maintainudptask::maintainudptask(csocket *sock, netprocessthread *netthread, const comargs *args /* = NULL */)
	: sockettask(sock, netthread, args)
{

}

maintainudptask::~maintainudptask()
{

}

bf_int_t maintainudptask::init(bf_time_t timeout /* = SOCKTASK_TIMEOUT */, bf_int_t sock_buflen /*  = 102400 */)
{
	if (!m_socket)
	{
		return BF_ERROR;
	}
	bf_int_t ret = m_socket->socket(SOCK_DGRAM);
	if (ret != BF_OK)
	{
		return BF_ERROR;
	}

	ret = m_socket->bind();
	if (ret != BF_OK)
	{
		return BF_ERROR;
	}

	return sockettask::init(timeout, sock_buflen);
}

bf_int_t maintainudptask::proc_msg(message *msg)
{
	return BF_OK;
}

bf_int_t maintainudptask::process_io_event(bf_int_t events)
{
	if ((events & BF_EPOLL_ERR) || (events & BF_EPOLL_HUP))
	{
		return BF_ERROR;
	}
	
	bf_int_t ret = BF_OK;
	if (events & BF_EPOLL_IN)
	{
		ret = recv_process();
		if (ret == BF_ERROR)
		{
			return BF_ERROR;
		}
	}

	if (events & BF_EPOLL_OUT)
	{
		ret = send_process();
		if (ret == BF_ERROR)
		{
			return BF_ERROR;
		}
	}
	return BF_OK;
}

bf_int_t maintainudptask::recv_process()
{
	bf_int_t recvlen = m_socket->recvfrom(m_recvbuf, UDP_RECV_BUF_LEN, m_addr);
	if (recvlen <= 0)
	{
		return BF_OK;
	}
	process_recv_packet(m_recvbuf, (bf_size_t)recvlen);
	return BF_OK;
}

bf_int_t maintainudptask::send_process()
{
	if (!m_cur_sendmsg)	
	{
		if (m_send_list.begin() != m_send_list.end())
		{
			m_cur_sendmsg = m_send_list.front();
			m_send_list.pop_front();
		}
		else
		{
			modify_epoll(BF_EPOLL_IN);
			return BF_OK;
		}
	}
	
	struct sockaddr_in &addr = ((udp_send_message*)m_cur_sendmsg)->get_info();
	m_socket->sendto(m_cur_sendmsg->get_buf(), m_cur_sendmsg->get_buflen(), addr);
	delete m_cur_sendmsg;
	m_cur_sendmsg = NULL;

	if (m_send_list.begin() == m_send_list.end())
	{
		modify_epoll(BF_EPOLL_IN);
	}
	else
	{
		m_cur_sendmsg = m_send_list.front();
		m_send_list.pop_front();
	}
	return BF_OK;
}

bf_int_t maintainudptask::process_recv_packet(bf_char_t *buf, bf_size_t buflen)
{
	bf_char_t *newbuf = new bf_char_t[buflen];
	memcpy(newbuf, buf, buflen);
	command *cmd = server::get()->get_classfactory()->gen_maintain_command(newbuf, buflen);
	if (!cmd)
	{
		delete [] newbuf;
		return BF_ERROR;
	}
	commandhelper cmdhelper(cmd);
	bf_int_t ret = cmd->process();
	if (ret != BF_OK)
	{
		return BF_ERROR;
	}
	put_send_packet(cmd->get_buf(), cmd->get_buflen());
	cmd->detach_buf();
	return BF_OK;
}

bf_int_t maintainudptask::put_send_packet(bf_char_t *buf, bf_size_t buflen)
{
	if (!buf || buflen == 0)
	{
		return BF_ERROR;
	}
	udp_send_message *sendmsg = new udp_send_message(buf, buflen, m_addr);
	bf_bool_t ifemtpy = m_send_list.empty();
	m_send_list.push_back(sendmsg);
	if (ifemtpy)
	{
		modify_epoll((BF_EPOLL_IN | BF_EPOLL_OUT));
	}
	return BF_OK;
}

